using Microsoft.Extensions.Configuration;
using PHMEE.Entities.Diagnosis;
using PHMEE.IRepositories.Diagnosis;
using TDengine.Data.Client;

namespace PHMEE.TDengineInfrastructure;

public class WaveDataAlarmTDRepository : IWaveDataAlarmTDRepository, IAsyncDisposable
{
    private readonly TDengineConnection _tdConnection;
    private readonly string _dbName;

    public WaveDataAlarmTDRepository(ITDConnectionFactory tdConnectionFactory, IConfiguration configuration)
    {
        _tdConnection = tdConnectionFactory.GetConnection();
        _dbName = configuration["TDengine:dbName"] ?? throw new ArgumentNullException("TDengine:dbName");
    }

    /// <summary>
    /// 获取原始数据
    /// </summary>
    /// <param name="pointId"></param>
    /// <param name="timeStamp"></param>
    /// <returns></returns>
    public async Task<float[]> GetAsync(Guid pointId, DateTime timeStamp)
    {
        await using var command = _tdConnection.CreateCommand();

        command.CommandText =
            $"SELECT * FROM {_dbName}.wda_{pointId:N} WHERE ts >= '{ConvertToFormattedString(timeStamp)}' and ts < '{ConvertToFormattedString(timeStamp.AddSeconds(1))}' ORDER BY ts ASC";

        await using var reader = await command.ExecuteReaderAsync();

        List<byte> rawValuesBytesList = [];

        while (await reader.ReadAsync())
        {
            var dataContentIndex = reader.GetOrdinal("data_content");
            var binDataContent = reader.GetFieldValue<byte[]>(dataContentIndex);
            rawValuesBytesList.AddRange(binDataContent);
        }

        var rawValuesBytes = rawValuesBytesList.ToArray();

        var floatArrLength = rawValuesBytes.Length / 4;
        var result = new float[floatArrLength];

        for (var i = 0; i < rawValuesBytes.Length; i += 4)
        {
            var index = i / 4;
            result[index] = BitConverter.ToSingle(rawValuesBytes, i);
        }

        return result;
    }

    /// <summary>
    /// 获取特征值和阈值
    /// </summary>
    /// <param name="pointId"></param>
    /// <param name="timeStamp"></param>
    /// <returns></returns>
    public async Task<WaveDataAlarmEigenValue?> GetFeatureValuesAsync(Guid pointId, DateTime timeStamp)
    {
        await using var command = _tdConnection.CreateCommand();

        command.CommandText =
            $"SELECT ts, acc_rms, acc_rms_warning, acc_rms_alarm, acc_avg_peak, acc_avg_peak_warning, acc_avg_peak_alarm, vel_rms, vel_rms_warning, vel_rms_alarm, acc_env_avg_peak FROM {_dbName}.wdae_{pointId:N} WHERE ts = '{ConvertToFormattedString(timeStamp)}' LIMIT 1";

        await using var reader = await command.ExecuteReaderAsync();

        WaveDataAlarmEigenValue result = new();

        if (await reader.ReadAsync())
        {
            result.Ts = reader.GetDateTime(0);
            result.AccRms = reader.GetFloat(1);
            result.AccRmsWarning = reader.GetFloat(2);
            result.AccRmsAlarm = reader.GetFloat(3);
            result.AccAvgPeak = reader.GetFloat(4);
            result.AccAvgPeakWarning = reader.GetFloat(5);
            result.AccAvgPeakAlarm = reader.GetFloat(6);
            result.VelRms = reader.GetFloat(7);
            result.VelRmsWarning = reader.GetFloat(8);
            result.VelRmsAlarm = reader.GetFloat(9);
            result.AccEnvAvgPeak = reader.GetFloat(10);
        }
        else
        {
            // 如果没有数据，返回 null
            return null;
        }

        return result;
    }

    // 暂时在这里转换时间格式
    private static string ConvertToFormattedString(DateTime dateTime)
    {
        return dateTime.ToString("yyyy-MM-ddTHH:mm:ss.fffZ");
    }

    public async ValueTask DisposeAsync()
    {
        await _tdConnection.CloseAsync();
        await _tdConnection.DisposeAsync();
        GC.SuppressFinalize(this);
    }

    ~WaveDataAlarmTDRepository()
    {
        DisposeAsync().AsTask().Wait();
    }
}